
#pragma once

#include "Main.h"

#include <string.h>

class List
{
private:

	u_int   m_uItems;
	u_int   m_uCapacity;
	void**  m_pItems;

	void DoubleCapacity()
	{
		void **pNewList;
		pNewList = new void*[m_uCapacity*2];
		if(m_pItems)
		{
			memset(pNewList,0,sizeof(void*)*m_uCapacity*2);
			memcpy(pNewList, m_pItems, sizeof(void*)*m_uCapacity);
			delete []m_pItems;
		}
		m_pItems = pNewList;
		m_uCapacity *= 2;
	}

public:  

	List()
	{
		m_uCapacity = 32;
		m_uItems = 0;
		m_pItems = new void*[m_uCapacity];
		memset(m_pItems,0,sizeof(void*)*m_uCapacity);
	}

	virtual ~List()
	{
		if(m_pItems)
		{
			delete []m_pItems;
		}
	}

	void* Get (int iIndex)
	{
		return Get( (u_int) iIndex );
	}
	void* Get (u_int uIndex)
	{
		if( uIndex > m_uItems - 1 )
		{
			return 0;
		}

		if(m_pItems)
		{
			return m_pItems[uIndex];
		}
		return 0;
	}
	const void* Get (int iIndex) const
	{
		return Get( (u_int) iIndex );
	}
	
	const void* Get(u_int uIndex) const
	{
		if( uIndex > m_uItems - 1 )
		{
			return 0;
		}

		if(m_pItems)
		{
			return m_pItems[uIndex];
		}
		return 0;
	}

	void* First (void) {
		if (m_pItems) {
			return m_pItems[0];
		}
		return 0;
	}
	void* Last (void) {
		if (m_pItems) {
			return m_pItems[m_uItems - 1];
		}
		return 0;
	}

	virtual int Add (void*  pItem)
	{      
		if(m_uItems == m_uCapacity)
		{
			DoubleCapacity();
		}
		
		m_pItems[m_uItems] = pItem;
		++m_uItems;
		return (m_uItems-1);
	}

	virtual void InsertBefore( int iIndex, void* pItem )
	{
		if(m_uItems == m_uCapacity)
		{
			DoubleCapacity();
		}

		memmove( &m_pItems[ iIndex + 1 ] , &m_pItems[ iIndex ], ( m_uItems - iIndex ) * sizeof( void* ) );
		++m_uItems;

		m_pItems[ iIndex ] = pItem;
	}

	virtual void InsertAfter( int iIndex, void* pItem )
	{
		if(m_uItems == m_uCapacity)
		{
			DoubleCapacity();
		}

		memmove( &m_pItems[ iIndex + 2 ] , &m_pItems[ iIndex + 1 ], ( m_uItems - iIndex - 1 ) * sizeof( void* ) );
		++m_uItems;

		m_pItems[ iIndex + 1 ] = pItem;
	}

	virtual void Delete  (int iIndex)
	{
		memmove(&m_pItems[iIndex],&m_pItems[iIndex+1],(m_uItems-(iIndex-1))*sizeof(void*));
		--m_uItems;
	}
	virtual void Clear   ()
	{
		if(m_pItems)
		{
			delete []m_pItems;
		}
		m_uCapacity = 32;
		m_uItems = 0;
		m_pItems = new void*[m_uCapacity];
		memset(m_pItems,0,sizeof(void*)*m_uCapacity);
	}
	virtual int IndexOf (void*  pItem)
	{
		if(m_pItems)
		{
			for(u_int uCnt=0;uCnt<m_uItems;++uCnt)
			{
				if(m_pItems[uCnt] == pItem)
				{
					return uCnt;
				}
			}
		}
		return -1;
	}
	virtual void Delete (void* pItem)
	{
		int iIndex = IndexOf(pItem);
		if(iIndex!=-1)
		{
			List::Delete(iIndex);
		}
	}
	virtual u_int Count () const
	{
		return m_uItems;
	}
};


template <class T>
class TypedList : public List
{

public:

	TypedList(bool bFreeObjects = false) : List(), bAutoDelete(bFreeObjects)
	{
	}

	virtual T* Get(int Index)
	{
		return (T*) List::Get(Index);
	}

	virtual T* Get(u_int uIndex)
	{
		return (T*) List::Get(uIndex);
	}

	virtual const T* Get(int Index) const
	{
		return (T*) List::Get(Index);
	}

	virtual const T* Get(u_int uIndex) const
	{
		return (T*) List::Get(uIndex);
	}

	virtual int Add(T* Item)
	{
		return List::Add(Item);
	}

	virtual void InsertBefore( const int iIndex, T* Item )
	{
		List::InsertBefore( iIndex, Item );
	}

	virtual void InsertAfter( const int iIndex, T* Item )
	{
		List::InsertAfter( iIndex, Item );
	}

	virtual void Delete(int Index)
	{
		if(bAutoDelete)
		{
			delete Get(Index);
		}
		List::Delete(Index);
	}

	virtual void Clear()
	{
		if(bAutoDelete)
		{
			for (u_int j=0; j<Count(); j++)
			{
				delete Get(j); 
			}
		}
		List::Clear();
	}

	virtual T* First(void)
	{
		return (T*)List::First();
	}

	virtual int IndexOf(T* Item)
	{
		return List::IndexOf(Item);
	}

	virtual T* Last(void)
	{
		return (T*) List::Last();
	}

	virtual void Remove(T* Item)
	{
		List::Delete(Item);
	}

	virtual void Delete(T* Item)
	{
		List::Delete(Item);
		if(bAutoDelete)
		{
			delete Item;
		}
	}

private:
	
	bool bAutoDelete;
};

//eof
